#region

using Microsoft.AspNetCore.Http;
using Vin.Extension.Framework.Base;
using Vin.Extension.Framework.Login.Attributes;
using Vin.Extension.Framework.Login.Dto.Entities;
using Vin.Extension.Framework.Login.Entities;
using Vin.Extension.Framework.Login.ServiceInterface;
using Vin.Extension.Framework.Sms.Email.Service;
using Vin.Extension.Framework.Sms.ServiceInterface;
using Vin.Tool.Attributes;
using Vin.Tool.Core.AssertCategory;
using Vin.Tool.Core.EnumCategory;
using Vin.Tool.Domain.ExceptionModel;

#endregion

namespace Vin.Extension.Framework.Login.Sms.Service;

[VinLoginService(VinLoginType.EmaildCode, VinLoginHandleType.Code, Way = "邮箱",
    Icon = "carbon-Email")]
public class VinEmailLoginService : VinFrameworkBaseService, ILoginService
{
    [Inject] private readonly ISysAccountBindService _sysAccountBindService = null!;

    [Inject] private readonly ISysAccountService _sysAccountService = null!;

    [Inject] private readonly ISysLoginService _sysLoginService = null!;

    [Inject(Key = VinEmailSmsService.Key)] private readonly IVinSmsService _vinSmsService = null!;

    public async Task<object> VerifyAsync(HttpContext context)
    {
        var receiver = context.Request.Query["receiver"];
        if (string.IsNullOrEmpty(receiver)) throw new BusinessException("手机号不能为空");

        if (!RegexTool.IsEmail(receiver)) throw new BusinessException("邮箱格式错误");

        if (GetVinTokenModelOrNull() != null)
        {
            if (await _sysAccountBindService.QueryAccountIdByBindAsync(VinLoginType.EmaildCode.GetName(), receiver!) !=
                null)
            {
                throw new BusinessException("邮箱已被使用");
            }
        }
        else
        {
            if (await _sysAccountBindService.QueryAccountIdByBindAsync(VinLoginType.EmaildCode.GetName(), receiver!) ==
                null)
                throw new BusinessException("邮箱未绑定");
        }


        return await _vinSmsService.SendCodeAsync("验证码登录", receiver!);
    }

    public async Task<string> LoginAsync(HttpContext context)
    {
        // 登录逻辑
        var loginBody = await context.Request.ReadFromJsonAsync<LoginBodyDto>();
        try
        {
            if (!RegexTool.IsEmail(loginBody?.UserName)) throw new BusinessException("邮箱格式错误");

            // 验证码
            if (!await _vinSmsService.VerifyCodeAsync(loginBody!.Uuid, loginBody.Code))
                throw new BusinessException("验证码错误");

            // 查询账号
            var accountId =
                await _sysAccountBindService.QueryAccountIdByBindAsync(VinLoginType.EmaildCode.GetName(),
                    loginBody.UserName);
            var account = await _sysAccountService.QueryByIdAsync(accountId);
            EmptyTool.CheckIsNull(account, "账号不存在");

            // 账号是否被禁用
            if (account.IsEnabled == false) throw new BusinessException("账号已被禁用");

            // 记录登录成功日志
            return await _sysLoginService.CreateTokenAsync(account, VinLoginType.EmaildCode.GetName(), loginBody);
        }
        catch (System.Exception e)
        {
            // 记录登录失败日志
            await _sysLoginService.AddLoginLogAsync(null, loginBody?.UserName, false, e.Message,
                VinLoginType.EmaildCode.GetName(),
                loginBody);
            throw;
        }
    }

    public async Task<bool> BindAsync(HttpContext context)
    {
        // 绑定逻辑
        var bindBody = await context.Request.ReadFromJsonAsync<LoginBodyDto>();

        if (!RegexTool.IsEmail(bindBody?.UserName)) throw new BusinessException("邮箱格式错误");

        // 验证码
        if (!await _vinSmsService.VerifyCodeAsync(bindBody!.Uuid, bindBody.Code))
            throw new BusinessException("验证码错误");

        await _sysAccountBindService.BindAsync(AccountId!.Value!, VinLoginType.EmaildCode.GetName(), bindBody.UserName,
            new SysAccountBindInfo(bindBody.UserName));

        return true;
    }

    public async Task<bool> UnBindAsync(HttpContext context)
    {
        // 解绑
        await _sysAccountBindService.UnBindAsync(AccountId!.Value, VinLoginType.EmaildCode.GetName());
        return true;
    }
}